package gUploadFile

import (
	"errors"
	"fmt"
	"gitee.com/zjlsliupei/ghelp"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/rs/xid"
	"github.com/tidwall/gjson"
	"log"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
)

type AliyunOss struct {
	// {"accessKey":"xxxxx","secret":"xxxx","bucketName":"wensi-zhanlang","endPoint":"oss-cn-hangzhou.aliyuncs.com","prefix":"/my-path","groupPattern":"DATETIME::{2006};$CORPID$;DATETIME::{01-02}","maxSize":1048576,"allowExt":".jpg", "denyExt":".exe"}
	// accessKey: 阿里云accessKey, 必填
	// secret: 阿里云secret, 必填
	// bucketName: oss bucketName, 必填
	// endPoint: oss endPoint, 必填
	// prefix: 前辍目录，可选
	// groupPattern: 目录分组模式，可选，"DATETIME::{2006-01-02};$CORPID$"，多级目录以;分开。其中DATETIME为系统自动模式，2006-01-02表里日期格式。自定义变量以$$包果，如果在SaveUploadFiles的时候传入变量，会自动替换变量
	// maxSize: 允许上传最大文件，可选，单位byte
	// allowExt: 扩展名白名单，可选，多个扩展名用|分割
	// denyExt: 扩展名黑名单，可选，多个扩展名用|分割
	option gjson.Result
	tmpDir string
	client *oss.Client
	bucket *oss.Bucket
}

func NewAliyunOss(option string) (AliyunOss, error) {
	_option := gjson.Parse(option)
	if !_option.Get("accessKey").Exists() {
		return AliyunOss{}, errors.New("accessKey is required")
	}
	if !_option.Get("secret").Exists() {
		return AliyunOss{}, errors.New("secret is required")
	}
	if !_option.Get("bucketName").Exists() {
		return AliyunOss{}, errors.New("bucketName is required")
	}
	if !_option.Get("endPoint").Exists() {
		return AliyunOss{}, errors.New("endPoint is required")
	}
	l := AliyunOss{
		option: _option,
	}
	var err error
	l.client, err = oss.New(_option.Get("endPoint").String(), _option.Get("accessKey").String(), _option.Get("secret").String())
	if err != nil {
		log.Println("create oss client Error:", err)
		return l, err
	}
	l.bucket, err = l.client.Bucket(_option.Get("bucketName").String())
	if err != nil {
		log.Println("select oss bucket Error:", err)
		return l, err
	}
	return l, err
}

func (l AliyunOss) SaveUploadFiles(headers []*multipart.FileHeader, groupParam map[string]string) ([]File, error) {
	files := make([]File, 0)
	if len(headers) < 1 {
		return files, errors.New("have no files")
	}
	// 转化成file
	var fileMetas []FileMeta
	for _, f := range headers {
		fileMetas = append(fileMetas, FileMeta{
			Filename: f.Filename,
			Size:     f.Size,
			Ext:      strings.ToLower(filepath.Ext(f.Filename)),
		})
	}

	// 先检查文件合法性
	for _, v := range fileMetas {
		if err := doBeforeSaveFunc(v, l.option); err != nil {
			return files, err
		}
	}
	// 再执行上传
	for _, v := range headers {
		if f, err := l.saveUploadFile(v, groupParam); err != nil {
			return files, err
		} else {
			files = append(files, f)
		}
	}
	return files, nil
}

func (l AliyunOss) saveUploadFile(header *multipart.FileHeader, groupParam map[string]string) (File, error) {
	f, err := header.Open()
	if err != nil {
		return File{}, err
	}
	defer f.Close()
	filePath := l.createFilepath(header.Filename, groupParam)
	// 上传至oss
	err = l.bucket.PutObject(filePath, f)
	fmt.Println("111", filePath)
	if err != nil {
		return File{}, err
	}
	_file := File{
		Filename:    filepath.Base(filePath),
		Filepath:    filePath,
		Size:        header.Size,
		Ext:         strings.ToLower(filepath.Ext(filePath)),
		RawFilename: header.Filename,
	}
	return _file, err
}

func (l AliyunOss) UploadLocalFile(filename string, groupParam map[string]string) (File, error) {
	if !ghelp.IsFile(filename) {
		return File{}, errors.New("file not exists")
	}
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return File{}, err
	}
	// 先检查文件合法性
	if er := doBeforeSaveFunc(FileMeta{
		Filename: filename,
		Size:     fileInfo.Size(),
		Ext:      strings.ToLower(filepath.Ext(filename)),
	}, l.option); er != nil {
		return File{}, er
	}

	filePath := l.createFilepath(filename, groupParam)
	// 上传至oss
	err = l.bucket.PutObjectFromFile(filePath, filename)
	if err != nil {
		return File{}, err
	}
	_file := File{
		Filename:    filepath.Base(filePath),
		Filepath:    filePath,
		Size:        fileInfo.Size(),
		Ext:         strings.ToLower(filepath.Ext(filePath)),
		RawFilename: filename,
	}
	return _file, err
}

func (l AliyunOss) CopyFile(objectName string, groupParam map[string]string) (File, error) {
	filePath := l.createFilepath(objectName, groupParam)
	// 拷贝oss
	_, err := l.bucket.CopyObject(objectName, filePath)

	if err != nil {
		return File{}, err
	}

	_, err = l.bucket.GetObjectMeta(objectName)
	if err != nil {
		return File{}, err
	}
	_file := File{
		Filename:    filepath.Base(filePath),
		Filepath:    filePath,
		Size:        0,
		Ext:         strings.ToLower(filepath.Ext(filePath)),
		RawFilename: filePath,
	}
	return _file, err
}

func (l AliyunOss) DownloadFile(srcObjectName, srcFilename string) error {
	return l.bucket.GetObjectToFile(srcObjectName, srcFilename)
}

func (l AliyunOss) createFilepath(filename string, groupParam map[string]string) string {
	filePath := filepath.Join(
		l.option.Get("prefix").String(),
		generateByGroupPattern(l.option.Get("groupPattern").String(), groupParam),
		xid.New().String()+strings.ToLower(filepath.Ext(filename)),
	)
	return strings.ReplaceAll(filePath, "\\", "/")
}

// GetBucketHandle 获取默认的bucket句柄
